<template>
  <div class="json-formatter">
    <el-row :gutter="20">
      <!-- 输入区域 -->
      <el-col :span="24" style="margin-bottom: 20px">
        <el-card class="h-full">
          <template #header>
            <div class="card-header">
              <el-icon color="#67C23A">
                <document />
              </el-icon>
              <span class="ml-2">输入JSON</span>
              <div class="flex-grow" />
              <el-radio-group v-model="inputType" size="small">
                <el-radio-button label="text">文本</el-radio-button>
                <el-radio-button label="file">文件</el-radio-button>
              </el-radio-group>
            </div>
          </template>

          <template v-if="inputType === 'text'">
            <el-input
              v-model="inputJson"
              type="textarea"
              :rows="20"
              placeholder="请输入JSON字符串"
              @input="formatJson"
            />
          </template>
          <template v-else>
            <el-upload
              class="upload-area"
              accept=".json"
              :auto-upload="false"
              :show-file-list="false"
              @change="handleFileUpload"
            >
              <template #trigger>
                <el-button type="primary">
                  <el-icon class="mr-2">
                    <upload />
                  </el-icon>
                  选择文件
                </el-button>
              </template>
              <template #tip>
                <div class="el-upload__tip">只能上传 JSON 文件</div>
              </template>
            </el-upload>
          </template>

          <div class="mt-4">
            <el-button type="primary" @click="formatJson">格式化</el-button>
            <el-button type="info" @click="compressJson">压缩</el-button>
            <el-button type="danger" @click="clearInput">清空</el-button>
          </div>
        </el-card>
      </el-col>

      <!-- 输出区域 -->
      <el-col :span="24">
        <el-card class="h-full">
          <template #header>
            <div class="card-header">
              <el-icon color="#409EFF">
                <document-checked />
              </el-icon>
              <span class="ml-2">格式化结果</span>
              <div class="flex-grow" />
              <el-button link :icon="DocumentCopy" @click="copyToClipboard" />
              <el-button link :icon="Download" @click="downloadJson" />
            </div>
          </template>

          <pre ref="outputPre" class="formatted-json" v-html="highlightedJson" />
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { Document, DocumentChecked, Upload, Download, DocumentCopy } from '@element-plus/icons-vue';

const inputType = ref('text');
const inputJson = ref('');
const formattedJson = ref('');

const highlightedJson = computed(() => {
  if (!formattedJson.value) return '';
  // 简单的语法高亮
  return formattedJson.value
    .replace(/(".*?")/g, '<span class="json-string">$1</span>')
    .replace(/\b(true|false|null)\b/g, '<span class="json-keyword">$1</span>')
    .replace(/\b(\d+\.?\d*)\b/g, '<span class="json-number">$1</span>');
});

const formatJson = () => {
  try {
    if (!inputJson.value.trim()) {
      ElMessage.warning('请输入JSON字符串');
      return;
    }
    const obj = JSON.parse(inputJson.value);
    formattedJson.value = JSON.stringify(obj, null, 2);
    ElMessage.success('格式化成功');
  } catch (error) {
    ElMessage.error(`无效的JSON格式: ${error.message}`);
  }
};

const compressJson = () => {
  try {
    if (!inputJson.value.trim()) {
      ElMessage.warning('请输入JSON字符串');
      return;
    }
    const obj = JSON.parse(inputJson.value);
    formattedJson.value = JSON.stringify(obj);
    ElMessage.success('压缩成功');
  } catch (error) {
    ElMessage.error(`无效的JSON格式: ${error.message}`);
  }
};

const handleFileUpload = async file => {
  try {
    const text = await file.raw.text();
    inputJson.value = text;
    formatJson();
  } catch (error) {
    ElMessage.error(`文件读取失败: ${error.message}`);
  }
};

const clearInput = () => {
  inputJson.value = '';
  formattedJson.value = '';
};

const copyToClipboard = async () => {
  try {
    await navigator.clipboard.writeText(formattedJson.value);
    ElMessage.success('已复制到剪贴板');
  } catch (error) {
    ElMessage.error(`复制失败: ${error.message}`);
  }
};

const downloadJson = () => {
  if (!formattedJson.value) {
    ElMessage.warning('没有可下载的内容');
    return;
  }

  const blob = new Blob([formattedJson.value], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'formatted.json';
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
};
</script>

<style scoped>
.json-formatter {
  padding: 20px;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

.h-full {
  height: 100%;
}

.flex-grow {
  flex-grow: 1;
}

.ml-2 {
  margin-left: 0.5rem;
}

.mr-2 {
  margin-right: 0.5rem;
}

.mt-4 {
  margin-top: 1rem;
}

.formatted-json {
  font-family: 'Fira Code', monospace;
  white-space: pre-wrap;
  word-wrap: break-word;
  margin: 0;
  padding: 10px;
  background-color: var(--el-fill-color-light);
  border-radius: 4px;
  max-height: 600px;
  overflow-y: auto;
}

.upload-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  border: 2px dashed var(--el-border-color);
  border-radius: 6px;
}

:deep(.json-string) {
  color: var(--el-color-success);
}

:deep(.json-number) {
  color: var(--el-color-primary);
}

:deep(.json-keyword) {
  color: var(--el-color-danger);
}
</style>
